'use strict';

exports.__esModule = true;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

var _graphql = require('graphql');

var _base = require('./base');

var _base2 = _interopRequireDefault(_base);

var _utils = require('./utils');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /* flow */


function checkLimit(limit) {
  if (!Number.isInteger(limit)) {
    throw new TypeError('limit must be an integer');
  } else if (limit < 0) {
    throw new RangeError('limit must be a positive integer');
  }
}

function checkLength(limit, comparator, isValidLength) {
  return function (value) {
    if (isValidLength(value.length)) {
      return value;
    }
    throw new TypeError('String\'s length must be ' + comparator + ' ' + limit + ', got ' + value.length);
  };
}

/**
 * String scalar type that represents string data.
 * By itself, it is essentially the `GraphQLString` type.
 */

var StringScalar = function (_Base) {
  _inherits(StringScalar, _Base);

  function StringScalar() {
    _classCallCheck(this, StringScalar);

    return _possibleConstructorReturn(this, (StringScalar.__proto__ || Object.getPrototypeOf(StringScalar)).apply(this, arguments));
  }

  _createClass(StringScalar, [{
    key: 'min',


    /**
     * Specifies the minimum number of string characters allowed.
     */
    value: function min(limit) {
      checkLimit(limit);
      if (limit > this._max) {
        throw new RangeError('limit cannot be larger than max length');
      } else if (typeof this._len !== 'undefined') {
        throw new RangeError('Minimum length cannot have a exact length');
      }

      var obj = this.clone();
      obj._min = limit;
      obj._func.push(checkLength(limit, 'at least', function (length) {
        return length >= limit;
      }));
      return obj;
    }

    /**
     * Specifies the maximum number of string characters allowed.
     */

  }, {
    key: 'max',
    value: function max(limit) {
      checkLimit(limit);
      if (limit < this._min) {
        throw new RangeError('limit cannot be smaller than min length');
      } else if (typeof this._len !== 'undefined') {
        throw new RangeError('Maximum length cannot have a exact length');
      }

      var obj = this.clone();
      obj._max = limit;
      obj._func.push(checkLength(limit, 'at most', function (length) {
        return length <= limit;
      }));
      return obj;
    }

    /**
     * Specifies the exact number of string characters required.
     */

  }, {
    key: 'length',
    value: function length(limit) {
      checkLimit(limit);
      if (typeof this._min !== 'undefined' || typeof this._max !== 'undefined') {
        throw new RangeError('Exact length cannot have a min or max limit');
      }

      var obj = this.clone();
      obj._len = limit;
      obj._func.push(checkLength(limit, 'exactly', function (length) {
        return length === limit;
      }));
      return obj;
    }

    /**
     * Specifies the length of the string to be truncated to if it exceeds.
     */

  }, {
    key: 'truncate',
    value: function truncate(limit) {
      checkLimit(limit);

      var obj = this.clone();
      obj._func.push(function (value) {
        return value.substring(0, limit);
      });
      return obj;
    }

    /**
     * Requires the string value to only contain a-z, A-Z, and 0-9.
     */

  }, {
    key: 'alphanum',
    value: function alphanum() {
      var obj = this.clone();
      obj._func.push(function (value) {
        if (/^[a-zA-Z0-9]+$/.test(value)) {
          return value;
        }
        throw new TypeError('String must only contain alpha-numeric characters');
      });
      return obj;
    }

    /**
     * Requires the string value to be a credit card number.
     */

  }, {
    key: 'creditCard',
    value: function creditCard() {
      var obj = this.clone();
      obj._func.push(function (value) {
        var i = value.length;
        var sum = 0;
        var mul = 1;

        /* eslint-disable */
        while (i--) {
          var char = value.charAt(i) * mul;
          sum += char - (char > 9) * 9;
          mul ^= 3;
        }
        /* eslint-enable */

        if (sum % 10 === 0 && sum > 0) {
          return value;
        }
        throw new TypeError('String must be a credit card number');
      });
      return obj;
    }

    /**
     * Requires the string value to match the regex test.
     * @param {RegExp} pattern
     * @param {boolean} [options= { name: '', invert: false }] `name` for regexp pattern and `invert` to disallow pattern instead.
     */

  }, {
    key: 'regex',
    value: function regex(pattern) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      var isRegExp = pattern instanceof RegExp;
      if (!isRegExp) {
        throw new TypeError('pattern must be a regex object');
      }

      var isValidFlag = !options.invert || false;
      var name = options.name || '';

      var conditionText = isValidFlag ? 'must' : 'must not';
      var obj = this.clone();
      obj._func.push(function (value) {
        if (pattern.test(value) === isValidFlag) {
          return value;
        }
        throw new TypeError('String ' + conditionText + ' match regexp ' + name);
      });
      return obj;
    }

    /**
     * Replaces the regex matches of the string with the `replacement`. Equivalent to `String.prototype.replace`.
     */

  }, {
    key: 'replace',
    value: function replace(pattern, replacement) {
      var obj = this.clone();
      obj._func.push(function (value) {
        return value.replace(pattern, replacement);
      });
      return obj;
    }

    /**
     * Trims the string.
     */

  }, {
    key: 'trim',
    value: function trim() {
      var obj = this.clone();
      obj._func.push(function (value) {
        return value.trim();
      });
      return obj;
    }

    /**
     *
     */

  }, {
    key: 'uppercase',
    value: function uppercase() {
      var obj = this.clone();
      obj._func.push(function (value) {
        return value.toLocaleUpperCase();
      });
      return obj;
    }

    /**
     *
     */

  }, {
    key: 'lowercase',
    value: function lowercase() {
      var obj = this.clone();
      obj._func.push(function (value) {
        return value.toLocaleLowerCase();
      });
      return obj;
    }

    /**
     * Requires the string to be a valid base64 string.
     */

  }, {
    key: 'base64',
    value: function base64() {
      var base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
      return this.regex(base64Regex, { name: 'base64' });
    }

    /**
     * Requires the string to be a valid hexadecimal string.
     */

  }, {
    key: 'hex',
    value: function hex() {
      var regex = /^[a-f0-9]+$/i;
      return this.regex(regex, { name: 'hexadecimal' });
    }
  }, {
    key: 'create',
    value: function create() {
      var validate = (0, _utils.compose)(this._func);
      function coerce(value) {
        return validate(String(value));
      }
      this.serialize = coerce;
      this.parseValue = coerce;
      this.parseLiteral = function (ast) {
        return ast.kind === _graphql.Kind.STRING ? validate(ast.value) : null;
      };
      return _get(StringScalar.prototype.__proto__ || Object.getPrototypeOf(StringScalar.prototype), 'create', this).call(this);
    }
  }]);

  return StringScalar;
}(_base2.default);

exports.default = StringScalar;